package com.xiashitech.agent.instrumentation.struts2.api.inst;

import com.xiashitech.agent.config.StartConfig;
import com.xiashitech.agent.instrumentation.context.SpringApplicationContext;
import com.xiashitech.interfaces.agent.dto.api.*;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class XSStruts2AllApiDeal {
    public static List<Api> extractApi(Object packageConfig) {
        List<Api> apis = new ArrayList();
        try {
            Object obj = SpringApplicationContext.getApplicationContext();
            if(obj == null )
                return apis;

            Method gf = obj.getClass().getMethod("getBeanFactory");
            Object factory = gf.invoke(obj);
            Method methodGetBeanDefinition = factory.getClass().getMethod("getBeanDefinition",String.class);
            if(methodGetBeanDefinition == null)
                return apis;

            Map<String, Object> actions = (Map<String, Object>) packageConfig.getClass().getMethod("getActionConfigs").invoke(packageConfig);
            if(actions ==  null || actions.size() == 0)
                return apis;
            String namespace = (String) packageConfig.getClass().getMethod("getNamespace").invoke(packageConfig);
            String packageName = (String) packageConfig.getClass().getMethod("getName").invoke(packageConfig);
            actions.forEach((key, action) -> {
                try {
                    // 通过 struts2 配置获取 beanName，然后通过 spring 获取到对应的 className，获取 bean 的 Class
                    String beanName = (String) action.getClass().getMethod("getClassName").invoke(action); // 对应是 beanName，如：tongchengAction
                    String actionName = (String)action.getClass().getMethod("getName").invoke(action); // 如：*CoreTc
                    String methodStr = (String)action.getClass().getMethod("getMethodName").invoke(action); // 如：{1}，可能为空
                    Api api = new Api();
                    api.setPackageName(packageName);
                    api.setActionNamespace(namespace);
                    api.setActionName(actionName);
                    api.setBeanName(beanName);
                    // 设置方法 HttpMethod
                    List<HttpMethod> hms = new ArrayList<>();
                    hms.add(HttpMethod.builder().name("GET").build());
                    api.setHttpMethods(hms);
                    // 设置路径
                    List<Path> paths = new ArrayList<>();
                    String partPath = "/";
                    if (namespace.endsWith("/"))
                        partPath = "";
                    //paths.add(Path.builder().name(namespace + partPath + actionName +".action" + "," + packageName + "_" + beanName + "_" + methodStr).build());
                    // 这里的 methodStr 应该时规则型，如：{1}
                    if (methodStr == null || methodStr.isEmpty())
                        methodStr = "";
                    else
                        methodStr = "!" + methodStr;
                    paths.add(Path.builder().name(namespace + partPath + actionName + ":" + beanName + "::" + methodStr).build());
                    api.setPaths(paths);

                    // 设置其他 method
                    Object definition = null;
                    try {
                        definition = methodGetBeanDefinition.invoke(factory, beanName); // 当指定的 beanName 不存在时，会报异常，skip，也可能是动态的，如：{2}
                    } catch (Exception ec) {
                        if(!"org.springframework.beans.factory.NoSuchBeanDefinitionException".equalsIgnoreCase(ec.getCause().getClass().getName()))
                            StartConfig.throwableStackPrinter(ec);
                    }
                    if(definition != null) {
                        String className = (String) definition.getClass().getMethod("getBeanClassName").invoke(definition);
                        api.setActionClassName(className);
                        Class clsz = Class.forName(className);
                        Method[] actionMethods = clsz.getMethods();
                        for (Method mt : actionMethods) {
                            boolean isPublic = Modifier.isPublic(mt.getModifiers());
                            boolean isReturnString = String.class == mt.getReturnType();
                            boolean isNoParam = mt.getParameters().length == 0;
                            if (isPublic && isNoParam && isReturnString) {
                                // api.setMethodName(mt.getName()); // 这里会先后覆盖，先不赋值了
                                paths.add(Path.builder().name(namespace + partPath + actionName + ":" + beanName + ":" + className + "!" + mt.getName()).build());
                            }
                        }
                    }
                    // 设置请求 content-type
                    List<Consumes> consumes = new ArrayList<>();
                    consumes.add(Consumes.builder().name("application/x-www-form-urlencoded").build());
                    api.setConsumes(consumes);
                    // 设置响应 content-type
                    List<Produces> produces = new ArrayList<>();
                    produces.add(Produces.builder().name("text/html; charset=utf-8").build());
                    api.setProduces(produces);
                    // 设置请求参数
                    List<Params> reqparams = new ArrayList<>();
                    api.setRequestParams(reqparams);
                    // 设置响应参数
                    List<Params> respparams = new ArrayList<>();
                    respparams.add(Params.builder().name("Object").type("Object").build());
                    api.setResponseParams(respparams);

                    apis.add(api);
                } catch (Exception ee) {
                    StartConfig.throwableStackPrinter(ee);
                }
            });
        } catch (Throwable e) {
            StartConfig.throwableStackPrinter(e);
        }
        return apis;
    }
}
